package co.edu.udea.iw.prestamos.bl;

import java.util.Set;

import javax.validation.ConstraintViolation;
import javax.validation.Validator;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.stereotype.Service;

import co.edu.udea.iw.prestamos.modelo.dao.UsuarioDAO;
import co.edu.udea.iw.prestamos.modelo.dto.Respuesta;
import co.edu.udea.iw.prestamos.modelo.dto.Usuario;
import co.edu.udea.iw.prestamos.util.ConstantesEstaticas;
import co.edu.udea.iw.prestamos.util.exception.DatabaseException;
import co.edu.udea.iw.prestamos.util.exception.RegistryNotFoundException;
import co.edu.udea.iw.prestamos.util.logger.Log;
import co.edu.udea.iw.prestamos.util.ppt.LeerPropiedades;
import co.edu.udea.iw.prestamos.util.seguridad.Autenticacion;

/**
 * Lógica de negocio para la gestión de los usuarios.
 * 
 * @author Dave Rivera <daverivera90@gmail.com>
 * @since 16-07-2014
 * @version 1.0
 */
@Configurable
@Service("usuarioBL")
public class UsuarioBL {
	
	/**
	 * Se inyectan las dependencias de la clase.
	 */
	@Autowired
	private UsuarioDAO usuarioDao;
	
	@Autowired
    private Validator validator;
	
	@Autowired
	private LeerPropiedades leerPropiedades;
	
	@Autowired
	private Autenticacion autenticacion;
	
	/**
	 * Registra un usuario en el sistema. Si la información de registro pasada
	 * como parámetro está incompleta, o el usuario ya existe, se retorna una
	 * respuesta de error, y no se completa el registro.
	 * 
	 * @param usuario Objeto con la información del usuario nuevo.
	 * @return respuesta con el resultado de la operación.
	 */
	public Object registrarUsuario(Usuario usuario) {	
		Respuesta respuesta = new Respuesta();
		
		if (usuario == null){
			respuesta.setTipo(Respuesta.ERROR);
			respuesta.setMensaje(
				leerPropiedades.leerPropiedad(
					LeerPropiedades.PROPERTIES_RESPUESTAS,
					ConstantesEstaticas.USUARIO_REGISTRO_ERROR_BD
				)
			);
			
			return respuesta;
		}
		
		// Setear el salt
		usuario.setSalt(autenticacion.generarSalt());
		
		//Verificar que tenga todos los campos obligatorios
		Set< ConstraintViolation<Usuario> > constraintViolations =
			validator.validate( usuario );
		
		if (!constraintViolations.isEmpty()){
			Log.log(
				getClass(),
				leerPropiedades.leerPropiedad(
					LeerPropiedades.PROPERTIES_RESPUESTAS,
					ConstantesEstaticas.USUARIO_REGISTRO_ERROR_MISSINGDATA
				) + ": " + constraintViolations.size(),
				Log.INFO,
				null
			);
			
			Log.log(
				getClass(),
				constraintViolations.toString(),
				Log.INFO,
				null
			);
			
			respuesta.setTipo(Respuesta.ERROR);
			respuesta.setMensaje(constraintViolations.toString());
			
			return respuesta;
		}
		
		// Verificar que el usuario no exista en la bd
		try {
			usuarioDao.obtenerPorId(usuario.getCedula());
			
			respuesta.setTipo(Respuesta.ERROR);
			respuesta.setMensaje(
				leerPropiedades.leerPropiedad(
					LeerPropiedades.PROPERTIES_RESPUESTAS,
					ConstantesEstaticas.USUARIO_REGISTRO_ERROR_DUPLICATE
				)
			);
			
			return respuesta;
		} catch (RegistryNotFoundException e) {
			Log.log(
				getClass(),
				"Registro de usuario. Cedula: " + usuario.getCedula()
					+ " Nombre: " + usuario.getNombres(),
				Log.INFO,
				null
			);
		}
		
		// Crear el password seguro
		String password = autenticacion.generarSecurePassword(
			usuario.getPassword(),
			usuario.getSalt()
		);
		
		usuario.setPassword(password);
		
		// Almacenar el usuario
		try {
			usuarioDao.crear(usuario);
			
			respuesta.setTipo(Respuesta.SUCCESS);
			respuesta.setMensaje(
				leerPropiedades.leerPropiedad(
					LeerPropiedades.PROPERTIES_RESPUESTAS, 
					ConstantesEstaticas.USUARIO_REGISTRO_SUCCESS
				)
			);
			
			return respuesta;
			
						
		} catch (DatabaseException e) {
			Log.log(
				getClass(),
				leerPropiedades.leerPropiedad(
					LeerPropiedades.PROPERTIES_RESPUESTAS,
					ConstantesEstaticas.USUARIO_REGISTRO_ERROR_BD
				),
				Log.ERROR,
				e
			);
		}
		
		respuesta.setTipo(Respuesta.ERROR);
		respuesta.setMensaje(
			leerPropiedades.leerPropiedad(
				LeerPropiedades.PROPERTIES_RESPUESTAS,
				ConstantesEstaticas.USUARIO_REGISTRO_ERROR_BD
			)
		);
		
		return respuesta;
	}	

}
